package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.lkd.common.VMSystem;
import com.lkd.conf.OrderConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.VendoutReq;
import com.lkd.contract.VendoutReqData;
import com.lkd.contract.VendoutResp;
import com.lkd.contract.server.OrderCheck;
import com.lkd.dao.OrderDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.feignService.UserService;
import com.lkd.feignService.VMService;
import com.lkd.service.OrderCollectService;
import com.lkd.service.OrderService;
import com.lkd.utils.JsonUtil;
import com.lkd.viewmodel.*;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    //@Autowired
    //private MqttProducer mqttProducer;


    @Autowired
    private OrderCollectService orderCollectService;

    @Autowired
    private VMService vmService;

    @Autowired
    private UserService userService;

    @Autowired
    private MqttProducer mqttProducer;

    @Autowired
    private RestHighLevelClient esClient;

    @Override
    public OrderEntity createOrder(CreateOrder createOrder) {
        VendingMachineViewModel vm = vmService.getVMInfo(createOrder.getInnerCode());
        SkuViewModel sku = vmService.getSku(createOrder.getInnerCode(), createOrder.getSkuId());
        OrderEntity orderEntity = new OrderEntity();
        //计算合作商分账金额
        PartnerViewModel partner = userService.getPartner(vm.getOwnerId());
        orderEntity.setOwnerId(vm.getOwnerId());
        Integer ratio = partner.getRatio();
        BigDecimal ratiod = new BigDecimal(ratio);
        BigDecimal realPrice = new BigDecimal(sku.getRealPrice());
        BigDecimal divide = ratiod.divide(new BigDecimal(100));
        orderEntity.setBill(realPrice.multiply(divide).intValue());

        orderEntity.setAddr(vm.getNodeAddr());
        orderEntity.setNodeId(vm.getNodeId());
        orderEntity.setNodeName(vm.getNodeName());
        orderEntity.setSkuId(sku.getSkuId());
        orderEntity.setSkuName(sku.getSkuName());
        orderEntity.setAmount(sku.getRealPrice());
        orderEntity.setClassId(sku.getClassId());
        orderEntity.setPrice(sku.getPrice());
        orderEntity.setBusinessId(vm.getBusinessId());
        orderEntity.setBusinessName(vm.getBusinessName());
        orderEntity.setInnerCode(createOrder.getInnerCode());
        orderEntity.setOpenId(createOrder.getOpenId());
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_NOPAY);
        orderEntity.setRegionId(vm.getRegionId());
        orderEntity.setRegionName(vm.getRegionName());
        orderEntity.setOrderNo(createOrder.getInnerCode() + createOrder.getSkuId() + System.nanoTime());
        //微信支付
        orderEntity.setPayType(createOrder.getPayType());

        orderEntity.setStatus(VMSystem.ORDER_STATUS_CREATE);
        orderEntity.setOwnerId(vm.getOwnerId());

        //将订单放入延迟队列中 10分钟后检查支付状态
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setOrderNo(orderEntity.getOrderNo());
        try {
            mqttProducer.send("$delayed/60/" + OrderConfig.ORDER_DELAY_CHECK_TOPIC, 2, orderCheck);
        } catch (Exception e) {
            log.error("send to is error:" + e);
        }

        //todo: 合作商分成计算

        this.save(orderEntity);


        return orderEntity;
    }


    @Override
    public boolean vendoutResult(VendoutResp vendoutResp) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderNo(vendoutResp.getVendoutResult().getOrderNo());
        UpdateWrapper<OrderEntity> uw = new UpdateWrapper<>();
        LambdaUpdateWrapper<OrderEntity> lambdaUpdateWrapper = uw.lambda();
        lambdaUpdateWrapper.set(OrderEntity::getPayStatus, 1);
        if (vendoutResp.getVendoutResult().isSuccess()) {
            lambdaUpdateWrapper.set(OrderEntity::getStatus, VMSystem.ORDER_STATUS_VENDOUT_SUCCESS);
        } else {
            lambdaUpdateWrapper.set(OrderEntity::getStatus, VMSystem.ORDER_STATUS_VENDOUT_FAIL);
        }
        lambdaUpdateWrapper.eq(OrderEntity::getOrderNo, vendoutResp.getVendoutResult().getOrderNo());

        return this.update(lambdaUpdateWrapper);
    }


    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo, orderNo);

        return this.getOne(qw);
    }

    @Override
    public Boolean cancel(String orderNo) {
        var order = this.getByOrderNo(orderNo);
        if (order.getStatus() > VMSystem.ORDER_STATUS_CREATE)
            return true;

        order.setStatus(VMSystem.ORDER_STATUS_INVALID);
        order.setCancelDesc("用户取消");

        return true;
    }

    /**
     * 微信支付完成
     *
     * @param orderNo
     * @return
     */
    @Override
    public Boolean payComePlated(String orderNo) {
        //发送出货通知
        sendVendout(orderNo);
        return true;
    }

    /**
     * 出货
     *
     * @param orderNo
     */
    private void sendVendout(String orderNo) {
        OrderEntity orderEntity = this.getByOrderNo(orderNo);

        VendoutReqData reqData = new VendoutReqData();
        reqData.setOrderNo(orderNo);
        reqData.setPayPrice(orderEntity.getAmount());
        reqData.setPayType(Integer.parseInt(orderEntity.getPayType()));
        reqData.setSkuId(orderEntity.getSkuId());
        reqData.setTimeout(60);
        reqData.setRequestTime(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));

        //向售货机发送出货请求
        VendoutReq req = new VendoutReq();
        req.setVendoutData(reqData);
        req.setSn(System.nanoTime());
        req.setInnerCode(orderEntity.getInnerCode());
        req.setNeedResp(true);
        //向售货机发送出货请求
        mqttProducer.send(TopicConfig.getVendoutTopic(orderEntity.getInnerCode()), 2, req);
    }

    /**
     * 查询订单
     *
     * @param pageIndex
     * @param pageSize
     * @param orderNo
     * @param openId
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public Pager<OrderViewModel> search(Integer pageIndex, Integer pageSize, String orderNo, String openId, String startDate, String endDate) {
        SearchRequest request = new SearchRequest("order");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //根据订单号查询
        if (!Strings.isNullOrEmpty(orderNo)) {
            boolQuery.must(QueryBuilders.termQuery("order_no", orderNo));
        }
        //根据openId查询
        if (!Strings.isNullOrEmpty(openId)) {
            boolQuery.must(QueryBuilders.termQuery("open_id", openId));
        }
        //根据时间范围查询
        if (!Strings.isNullOrEmpty(startDate) && !Strings.isNullOrEmpty(endDate)) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("update_time");
            rangeQuery.gte(startDate);
            rangeQuery.lte(endDate);
            boolQuery.must(rangeQuery);
        }
        //按照最后更新时间由近到远的排序规则排序
        sourceBuilder.from((pageIndex - 1) * pageSize);
        sourceBuilder.size(pageSize);
        sourceBuilder.sort("update_time", SortOrder.DESC);
        sourceBuilder.trackTotalHits(true);
        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);

        try {
            SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            SearchHit[] searchHits = hits.getHits();
            ArrayList<OrderViewModel> orderList = Lists.newArrayList();
            for (SearchHit hit : searchHits) {
                OrderViewModel order = new OrderViewModel();
                String hitResult = hit.getSourceAsString();
                JsonNode jsonNode = JsonUtil.getTreeNode(hitResult);
                order.setId(jsonNode.findPath("id").asLong());
                order.setStatus(jsonNode.findPath("status").asInt());
                order.setBill(jsonNode.findPath("bill").asInt());
                order.setOwnerId(jsonNode.findPath("owner_id").asInt());
                order.setPayType(jsonNode.findPath("pay_type").asText());
                order.setOrderNo(jsonNode.findPath("order_no").asText());
                order.setInnerCode(jsonNode.findPath("inner_code").asText());
                order.setSkuName(jsonNode.findPath("sku_name").asText());
                order.setSkuId(jsonNode.findPath("sku_id").asLong());
                order.setPayStatus(jsonNode.findPath("pay_status").asInt());
                order.setBusinessName(jsonNode.findPath("business_name").asText());
                order.setBusinessId(jsonNode.findPath("business_id").asInt());
                order.setRegionId(jsonNode.findPath("region_id").asLong());
                order.setRegionName(jsonNode.findPath("region_name").asText());
                order.setPrice(jsonNode.findParent("price").asInt());
                order.setAmount(jsonNode.findPath("amount").asInt());
                order.setAddr(jsonNode.findParent("addr").asText());
                order.setOpenId(jsonNode.findPath("open_id").asText());

                order.setCreateTime(LocalDateTime.parse(jsonNode.findPath("create_time").asText(), DateTimeFormatter.ISO_DATE_TIME));
                order.setUpdateTime(LocalDateTime.parse(jsonNode.findPath("update_time").asText(), DateTimeFormatter.ISO_DATE_TIME));
                orderList.add(order);
            }
            Pager<OrderViewModel> pager = new Pager<>();
            pager.setTotalCount(response.getHits().getTotalHits().value);
            pager.setPageSize(response.getHits().getHits().length);
            pager.setCurrentPageRecords(orderList);
            pager.setPageIndex(pageIndex);
            return pager;

        } catch (Exception e) {
            log.error("查询es失败:" + e);
            return Pager.buildEmpty();
        }
    }

}
